#include "stdafx.h"
#include "xKernel/IxNode.h"
#include "xKernel/IxPaint.h"
#include "xKernel/IxBorderPaint.h"
#include "xKernel/IxFocusPaint.h"
#include "PaintSchedule.h"

CxPaintSchedule::CxPaintSchedule()
{}

CxPaintSchedule::~CxPaintSchedule()
{}


HRESULT CxPaintSchedule::AddView(IxView* pView)
{
    CComQIPtr<IxNode> spNode = pView;
    if (!pView || !spNode)
    {
        return E_INVALIDARG;
    }

    if (m_setViews.count(reinterpret_cast<ULONGLONG>(pView)) > 0)
    {
        return S_FALSE;
    }

    m_setViews.insert(reinterpret_cast<ULONGLONG>(pView));

    INT nDepth = 0;
    spNode->GetDepth(&nDepth);

    INT nZorder = 0;
    pView->GetZOrder(&nZorder);

    m_mapViews.insert(std::make_pair(std::make_pair(nDepth, nZorder), pView));

    _add_ancestor_view_recursive(CComQIPtr<IxNode>(pView));
    _add_child_view_recursive(CComQIPtr<IxNode>(pView));

    return S_OK;
}

HRESULT CxPaintSchedule::Paint(IxCanvas* pCanvas)
{
    VIEWMAP::iterator it = m_mapViews.begin();
    CComQIPtr<IxPaint> spPaint;
    CComQIPtr<IxBorderPaint> spBorderPaint;
    CComQIPtr<IxFocusPaint> spFocusPaint;
    while (it != m_mapViews.end())
    {
        spPaint = it->second;
        if (spPaint)
        {
            spPaint->Paint(pCanvas);
        }

        spBorderPaint = it->second;
        if (spBorderPaint)
        {
            spBorderPaint->BorderPaint(pCanvas);
        }

        spFocusPaint = it->second;
        if (spFocusPaint)
        {
            spFocusPaint->FocusPaint(pCanvas);
        }

        ++it;
    }

    m_setViews.clear();
    m_mapViews.clear();

    return S_OK;
}

void CxPaintSchedule::_add_ancestor_view_recursive(IxNode* pNode)
{
    if (!pNode)
    {
        return;
    }

    CComPtr<IxNode> spParentNode;
    pNode->GetParent(&spParentNode);

    CComQIPtr<IxView> spParentView = spParentNode;

    if (!spParentView
        || m_setViews.count(reinterpret_cast<ULONGLONG>(spParentView.p)) > 0)
    {
        return;
    }

    m_setViews.insert(reinterpret_cast<ULONGLONG>(spParentView.p));

    INT nDepth = 0;
    spParentNode->GetDepth(&nDepth);

    INT nZorder = 0;
    spParentView->GetZOrder(&nZorder);

    m_mapViews.insert(std::make_pair(std::make_pair(nDepth, nZorder), spParentView));

    _add_ancestor_view_recursive(spParentNode);
}

void CxPaintSchedule::_add_child_view_recursive(IxNode* pNode)
{
    if (!pNode)
    {
        return;
    }

    INT nCount = 0;
    pNode->GetChildrenCount(&nCount);

    if (0 == nCount)
    {
        return;
    }

    CComPtr<IxNode> spChildNode;
    CComQIPtr<IxView> spChildView;
    for (INT i = 0; i < nCount; ++i)
    {
        spChildNode = NULL;
        pNode->GetChildByIndex(i, &spChildNode);

        spChildView = spChildNode;
        if (spChildView)
        {
            if (0 == m_setViews.count(reinterpret_cast<ULONGLONG>(spChildView.p)))
            {
                m_setViews.insert(reinterpret_cast<ULONGLONG>(spChildView.p));

                INT nDepth = 0;
                spChildNode->GetDepth(&nDepth);

                INT nZorder = 0;
                spChildView->GetZOrder(&nZorder);

                m_mapViews.insert(std::make_pair(std::make_pair(nDepth, nZorder), spChildView));

                _add_child_view_recursive(spChildNode);
            }
        }
    }
}